package com.wan.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;

import com.wan.constants.TokenConstants;
import com.wan.util.JwtUtil;
import com.wan.util.R;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;


import java.util.List;

@Component
@Slf4j
public class HzitAuthFilter implements GlobalFilter, Ordered {
	@Autowired
	private StringRedisTemplate redisTemplate;
	@Autowired
	private WhiteListProperties whiteListProperties;

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		// 1. 获取请求路径
		String path = exchange.getRequest().getURI().getPath();
		log.info("Request path: {}", path);

		// 2. 白名单放行
		if (isWhiteListed(path)) {
			return chain.filter(exchange);
		}

		// 3. 校验认证请求头
		String token = extractTokenFromHeader(exchange.getRequest());
		if (StrUtil.isBlank(token)) {
			return unauthorizedResponse(exchange, "认证不成功！");
		}

		// 4. 解析 token
		Claims claims = JwtUtil.parseToken(token);
		if (claims == null) {
			return unauthorizedResponse(exchange, "Token信息丢失或无效！");
		}

		// 5. 校验 Redis 中是否存在 token
		if (!isTokenInRedis(claims)) {
			return unauthorizedResponse(exchange, "登录信息错误，请稍后重试！");
		}

		// 6. 放行请求
		return chain.filter(exchange);
	}

	// 2. 白名单路径匹配
	private boolean isWhiteListed(String path) {
		List<String> whiteList = whiteListProperties.getPaths();
		return whiteList.stream().anyMatch(path::contains);
	}

	// 3. 从请求头中提取 token
	private String extractTokenFromHeader(ServerHttpRequest request) {
		String header = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
		if (StrUtil.isBlank(header)) {
			return null;
		}
		return getToken(header);
	}

	// 4. 从请求头中提取 token 内容
	private String getToken(String header) {
		if (header.startsWith("Bearer ")) {
			return header.replaceAll(TokenConstants.PREFIX, "");
		}
		return null;
	}

	// 5. 校验 Redis 中是否存在有效 token
	private boolean isTokenInRedis(Claims claims) {
		String uuidToken = (String) claims.get(TokenConstants.JWT_TOKEN);
		String redisKey = getRedisKey(uuidToken);
		return redisTemplate.hasKey(redisKey);
	}

	// 6. 获取 Redis 键
	private String getRedisKey(String uuidToken) {
		return TokenConstants.REDIS_PREFIX + uuidToken;
	}
	// 7. 构建未授权的响应
	private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
		return webFluxResponseWriter(exchange, msg, HttpStatus.UNAUTHORIZED.value());
	}

	// 8. 将指定的信息输出到页面中
	private Mono<Void> webFluxResponseWriter(ServerWebExchange exchange, String msg, int code) {
		ServerHttpResponse response = exchange.getResponse();
		R fail = R.fail(code, msg);
		DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONString(fail).getBytes());
		return response.writeWith(Mono.just(buffer));
	}

	@Override
	public int getOrder() {
		return 0;
	}
}
